/*
 * Copyright © 2018 www.noark.xyz All Rights Reserved.
 *
 * 感谢您选择Noark框架，希望我们的努力能为您提供一个简单、易用、稳定的服务器端框架 ！
 * 除非符合Noark许可协议，否则不得使用该文件，您可以下载许可协议文件：
 *
 *        http://www.noark.xyz/LICENSE
 *
 * 1.未经许可，任何公司及个人不得以任何方式或理由对本框架进行修改、使用和传播;
 * 2.禁止在本项目或任何子项目的基础上发展任何派生版本、修改版本或第三方版本;
 * 3.无论你对源代码做出任何修改和改进，版权都归Noark研发团队所有，我们保留所有权利;
 * 4.凡侵犯Noark版权等知识产权的，必依法追究其法律责任，特此郑重法律声明！
 */
package xyz.noark.codec.output;

import com.alibaba.fastjson2.util.JDKUtils;
import sun.misc.Unsafe;

import java.io.Flushable;
import java.util.Arrays;

/**
 * 编码所用的输出流接口，具体编码规则看实际类
 *
 * @author 小流氓[176543888@qq.com]
 */
public class CodedOutputStreamImplUnsafe implements AutoCloseable, Flushable {
    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
    //private final OutputStream out;
    private final byte[] buffer;
    private int writeIndex;

    public CodedOutputStreamImplUnsafe() {
        this.buffer = new byte[1024];
        this.writeIndex = 0;
    }

    public void writeInt32(int value)  {
        //this.flushIfNotAvailable(10);
        bufferFixed32NoTag(value);
    }

    final void bufferFixed32NoTag(long value)  {
        // -16 到 127
        if (value >= -16 && value <= 127) {
            buffer[writeIndex++] = (byte) value;
        }
        //
        else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
            buffer[writeIndex++] = (byte) 0x83;
            buffer[writeIndex++] = (byte) value;
        }
        //
        else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
            buffer[writeIndex++] = (byte) 0x84;
            UNSAFE.putShort(buffer, writeIndex, (short) value);
            writeIndex += 2;
        }
        //
        else if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
            buffer[writeIndex++] = (byte) 0x85;
            UNSAFE.putInt(buffer, writeIndex, (int) value);
            writeIndex += 4;
        }
        //
        else {
            buffer[writeIndex++] = (byte) 0x86;
            UNSAFE.putLong(buffer, writeIndex, value);
            writeIndex += 8;
        }
    }

    public void writeInt64(long value)  {
        bufferFixed32NoTag(value);
    }

    public void writeString(String value)  {
        //System.out.println(value);


        byte[] bytes = JDKUtils.STRING_VALUE.apply(value);
        //byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
        this.writeInt32(bytes.length);
        //System.out.println(Arrays.toString(bytes));
        //byte[] bytes = ((byte[]) Platform.getObject(value, STRING_VALUE_FIELD_OFFSET));
        //byte[] bytes = value.getBytes(StandardCharsets.UTF_16);
        //System.out.println(Arrays.toString(bytes));
        System.arraycopy(bytes, 0, buffer, writeIndex, bytes.length);
        writeIndex += bytes.length;
        //buffer[writeIndex++]=
    }

    public void writeBytes(byte[] bytes)  {
        //System.out.println(value);
        this.writeInt32(bytes.length);
        System.arraycopy(bytes, 0, buffer, writeIndex, bytes.length);
        writeIndex += bytes.length;
        //buffer[writeIndex++]=
    }

    public void writeBoolean()  {
        UNSAFE.putByte(buffer, writeIndex++, (byte) 0x81);
    }

    @Override
    public void close()  {
        this.flush();

    }

    @Override
    public void flush()  {
        //out.flush();
    }

    public byte[] toByteArray() {
        return Arrays.copyOf(buffer, writeIndex);
    }
}